package com.bosi.ws.server;

import com.bosi.ws.server.impl.WebSocketChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Slf4j
public abstract class FastNettyWebSocketServer implements WebSocketServer {
    private Channel serverChannel;
    private NettyWebsocketServerConfig config;

    public void start(NettyWebsocketServerConfig config) {
        this.config = config;
        ServerBootstrap server = new ServerBootstrap();
        server.group(config.getBoosGroup(), config.getWorkerGroup());
        server.channel(NioServerSocketChannel.class);
        server.childHandler(config.getChildHandler());

        ChannelFuture future = server.bind(config.getPort());
        future.addListener(f -> {
            if (f.isDone() && f.isSuccess()) {
                this.serverChannel = future.channel();
                log.info("Start ws server success");
                log.info("boos group thread number {}", config.getBoosGroup().executorCount());
                log.info("worker group thread number {}", config.getWorkerGroup().executorCount());
            }
            if (f.isDone() && f.cause() != null) {
                log.error("Start ws server fail throw={}", f.cause().getMessage());
                future.channel().close();
            }
        });
    }

    public void start(final int port) {
        start(new NettyWebsocketServerConfig() {
            @Override
            public ChannelHandler getChildHandler() {
                return new WebSocketChannelInitializer(FastNettyWebSocketServer.this);
            }

            @Override
            public int getPort() {
                return port;
            }
        });
    }

    public void start() {
        start(8080);
    }

    public void stop() {
        if (serverChannel != null && serverChannel.isOpen()) {
            final int waitSec = 10;
            CountDownLatch latch = new CountDownLatch(1);
            serverChannel.close().addListener(f -> {
                config.getWorkerGroup().schedule(() -> {
                    log.info("Shutdown dispatcher success...");
                    config.getWorkerGroup().shutdownGracefully();
                    latch.countDown();
                }, waitSec - 2, TimeUnit.SECONDS);

                log.info("Close ws server socket success={}", f.isSuccess());
                config.getBoosGroup().shutdownGracefully();
            });

            try {
                boolean flag = latch.await(waitSec, TimeUnit.SECONDS);
                if(!flag){
                    log.warn("Shutdown ws server timeout");
                }
            } catch (InterruptedException e) {
                log.warn("Shutdown ws server interrupted exception={}", e.getMessage());
            }
        }
    }
}
